// 读写锁测试代码 -20230211-
#include <iostream>
#include <string>
#include <vector>
#include <pthread.h>
#include <unistd.h>
#include "log.hpp"  // 日志文件

typedef void* (*func_t)(void*);  // 设置函数指针

static const int RTHREAD  = 0;  // 读线程
static const int WTHREAD  = 1;  // 写线程

volatile int nums = 1000;  // volatile表示此变量不可优化到寄存器，存在对其修改的操作
pthread_rwlock_t rwlock;  // 读写锁对象

// 简单封装一下线程对象
class Thread
{
public:
    Thread(int flag, int num, func_t func)  // 什么线程 编号 回调函数
    :_func(func)
    {
        if (flag == RTHREAD) _id = "ReadThread-";
        else if (flag == WTHREAD) _id = "WriteThread-";
        else
        {
            std::cerr << "flag is RTHREAD and WTHREAD" << std::endl;
            exit(-1);  // 终止程序
        }

        _id += std::to_string(num);
    }

    void start()
    {
        // 启动线程
        pthread_create(&_tid, nullptr, _func, (void*)_id.c_str());
    }

    void join()
    {
        // 等待回收线程
        pthread_join(_tid, nullptr);
    }

private:
    pthread_t _tid;
    std::string _id;
    func_t _func;
};

// 对读写锁初始化函数
void initRwlock(int flag = RTHREAD)  // flag为上面的RTHREAD-读优先 WTHRERAD-写优先 默认读优先或者其余错误选项
{
    if (flag == WTHREAD)
    {
        pthread_rwlockattr_t attr;  // 属性类型，首先需要进行初始化
        pthread_rwlockattr_init(&attr);
        pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);  // 设置写者优先 -存在bug
        pthread_rwlock_init(&rwlock, &attr);
    }
    else pthread_rwlock_init(&rwlock, nullptr);  // 默认读者优先
}

// 读者回调函数
void* readThread(void* args)
{
    // 注意读写锁需要进行初始化以及确定优先级
    // 读者反复读取数据即可
    char* str = (char*) args;
    while (true)
    {
        pthread_rwlock_rdlock(&rwlock);  // 读者锁 读者同步 写者互斥
        // 临界资源区
        if (nums > 0) logMessage(NORMAL, "%s:%d", str, nums);
        else
        {
            pthread_rwlock_unlock(&rwlock);
            break;
        }
        pthread_rwlock_unlock(&rwlock);
        usleep(1);
    }
    return nullptr;
}

// 写者回调函数
void* writeThread(void* args)
{
    // 注意读写锁需要进行初始化以及确定优先级
    // 写者需要进行--操作
    char* str = (char*) args;
    while (true)
    {
        pthread_rwlock_wrlock(&rwlock);  // 写者锁 写者-读者互斥
        // 临界资源区
        if (nums > 0)
        {
            --nums;
            logMessage(WARNING, "%s进行了写操作!", str);
        }
        else
        {
            pthread_rwlock_unlock(&rwlock);
            break;
        }
        pthread_rwlock_unlock(&rwlock);
        usleep(1);
    }
    return nullptr;
}

// 对读者线程进行创建 - 启动函数函数
void readThreadCreate(std::vector<Thread*>& reads, int nums)
{
    // 创建 + 启动
    for (int i = 1; i <= nums; ++i)
    {
        reads.push_back(new Thread(RTHREAD, i, readThread));
        reads[i - 1]->start();
    }
}

// 对写者线程进行创建 - 启动函数函数
void writeThreadCreate(std::vector<Thread*>& writes, int nums)
{
    // 创建 + 启动
    for (int i = 1; i <= nums; ++i)
    {
        writes.push_back(new Thread(WTHREAD, i, writeThread));
        writes[i - 1]->start();
    }
}

// 对读线程进行等待
void readThreadJoin(std::vector<Thread*>& reads)
{
    for (int i = 0; i < reads.size(); ++i)
    {
        reads[i]->join();
        delete reads[i];  // 别忘了new的需要释放
    }
}

// 对写线程进行等待
void writeThreadJoin(std::vector<Thread*>& writes)
{
    for (int i = 0; i < writes.size(); ++i)
    {
        writes[i]->join();
        delete writes[i];  // 别忘了new的需要释放
    }
}

int main()
{
    // 主线程
    // 决定读读线程个数和写线程个数
    int readNums = 10;
    int writeNums = 2;
    // 初始化读写锁
    initRwlock(WTHREAD);  // 默认读优先
    // 创建多线程环境
    std::vector<Thread*> reads;
    std::vector<Thread*> writes;
    readThreadCreate(reads, readNums);
    writeThreadCreate(writes, writeNums);
    // 运行多线程后进行线程等待
    readThreadJoin(reads);
    writeThreadJoin(writes);
    //别忘了对读写锁变量进行释放
    pthread_rwlock_destroy(&rwlock);
    return 0;
}